home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2000 #4 / Amiga Plus CD - 2000 - No. 4.iso / Vollversion / CamD / development / devs / midi / internal.asm < prev    next >
Encoding:
Assembly Source File  |  2000-05-15  |  18.7 KB  |  750 lines

  1. ************************************************************************
  2. *                            C. A. M. D.                               *
  3. ************************************************************************
  4. * CMU Amiga Midi Driver - Carnegie Mellon University                   *
  5. * 1988                  - Commodore Amiga                              *
  6. *                                                                      *
  7. * Design & Development  - Roger B. Dannenberg                          *
  8. *                       - Jean-Christophe Dhellemmes                   *
  9. *                       - Bill Barton                                  *
  10. * Copyright 1989 Carnegie Mellon University                            *
  11. ************************************************************************
  12. *
  13. * internal.asm - Example CAMD MIDI Device Driver for internal serial
  14. *                port.
  15. *
  16. * This is merely an example.  The internal serial port is normally
  17. * managed by camd.library.
  18. *
  19. ************************************************************************
  20. * Date        | Change
  21. *-----------------------------------------------------------------------
  22. * 06-Jan-1990 : Created (BB)
  23. ************************************************************************
  24.  
  25.       nolist
  26.         include "exec/types.i"
  27.         include "exec/execbase.i"           ; for FlushDevice()
  28.         include "exec/macros.i"
  29.         include "hardware/cia.i"
  30.         include "hardware/custom.i"
  31.         include "hardware/intbits.i"
  32.         include "midi/camddevices.i"
  33.         include "resources/misc.i"
  34.       list
  35.  
  36.  
  37. Version  equ 0
  38. Revision equ 0
  39. Ports    equ 1
  40.  
  41.  
  42.         section driver,data
  43.  
  44.             ; external
  45.         xref    _AbsExecBase
  46.         xref    _custom
  47.         xref    _ciab
  48.  
  49.  
  50.         section driver,code
  51.  
  52.  
  53. ****************************************************************
  54. *
  55. *   Standard MIDI Device driver header
  56. *
  57. ****************************************************************
  58.  
  59. ; code at start of file in case anyone tries to execute us as a program
  60.  
  61.         entry   FalseStart
  62. FalseStart
  63.         moveq   #-1,d0
  64.         rts
  65.  
  66. MDD ; struct MidiDeviceData
  67.         dc.l    MDD_Magic       ; mdd_Magic
  68.         dc.l    Name            ; mdd_Name
  69.         dc.l    IDString        ; mdd_IDString
  70.         dc.w    Version         ; mdd_Version
  71.         dc.w    Revision        ; mdd_Revision
  72.         dc.l    Init            ; mdd_Init
  73.         dc.l    Expunge         ; mdd_Expunge
  74.         dc.l    OpenPort        ; mdd_OpenPort
  75.         dc.l    ClosePort       ; mdd_ClosePort
  76.         dc.b    Ports           ; mdd_NPorts
  77.         dc.b    0               ; mdd_Flags
  78.  
  79. Name        dc.b    'TriplePlay',0
  80. IDString    dc.b    'TriplePlay port MIDI device driver',0
  81.             ds.w    0   ; force word alignment
  82.  
  83.  
  84. ****************************************************************
  85. *
  86. *   Serial Port Stuff
  87. *
  88. ****************************************************************
  89.  
  90. SerFreq_NTSC equ    3579545
  91. SerFreq_PAL equ     3546895
  92.  
  93. MIDIBPS     equ     31250
  94.  
  95. SetSerPer   macro   ; freq
  96.         move.w  #(\1+MIDIBPS/2)/MIDIBPS-1,SerPer    ; bits 0-14: period.  bit 15: 9/8 bit selection
  97.         endm
  98.  
  99.  
  100. INTF_CLR    equ 0
  101.         BITDEF  INT,SET,INTB_SETCLR
  102.  
  103.             ; serdatr register bit def's (not found in any include file)
  104.  
  105.         BITDEF  SERDAT,OVRUN,15
  106.         BITDEF  SERDAT,RBF,14
  107.         BITDEF  SERDAT,TBE,13
  108.         BITDEF  SERDAT,TSRE,12
  109.  
  110.     STRUCTURE SerInt,IS_SIZE
  111.         UWORD   si_pad0
  112.         APTR    si_OldInt
  113.         APTR    si_Data
  114.         APTR    si_Code
  115.         LABEL   SerInt_Size
  116.  
  117.  
  118.         section driver,data         ; data
  119.  
  120. MiscBase    ds.l    1               ; misc.resource pointer
  121. SerPer      ds.w    1               ; serper value
  122. OldIntEna   ds.w    1               ; original value of TBE and RBF bits
  123.  
  124. MPD0 ; struct MidiPortData
  125.             dc.l    ActivateXmit
  126.  
  127. SerXmitInt
  128.             dc.l    0               ; ln_Succ
  129.             dc.l    0               ; ln_Pred
  130.             dc.b    NT_INTERRUPT    ; ln_Type
  131.             dc.b    0               ; ln_Pri
  132.             dc.l    Name            ; ln_Name
  133.             dc.l    SerXmitInt+si_Data ; is_Data
  134.             dc.l    XmitHandler     ; is_Code
  135.             dc.w    0               ; si_pad0
  136.             dc.l    0               ; si_OldInt
  137.             dc.l    0               ; si_Data
  138.             dc.l    0               ; si_Code
  139.  
  140. SerRecvInt
  141.             dc.l    0               ; ln_Succ
  142.             dc.l    0               ; ln_Pred
  143.             dc.b    NT_INTERRUPT    ; ln_Type
  144.             dc.b    0               ; ln_Pri
  145.             dc.l    Name            ; ln_Name
  146.             dc.l    SerRecvInt+si_Data ; is_Data
  147.             dc.l    RecvHandler     ; is_Code
  148.             dc.w    0               ; si_pad0
  149.             dc.l    0               ; si_OldInt
  150.             dc.l    0               ; si_Data
  151.             dc.l    0               ; si_Code
  152.  
  153.         section driver,code
  154.  
  155. ****************************************************************
  156. *
  157. *   MidiDeviceData Functions
  158. *
  159. ****************************************************************
  160.  
  161. ****************************************************************
  162. *
  163. *   Init
  164. *
  165. *   FUNCTION
  166. *       Gets called by CAMD after being LoadSeg'ed.
  167. *
  168. *   INPUTS
  169. *       None
  170. *
  171. *   RESULTS
  172. *       TRUE if successful, FALSE on failure.
  173. *
  174. ****************************************************************
  175.  
  176. init_reg reg a6
  177.  
  178. Init
  179.         movem.l init_reg,-(sp)
  180.  
  181.         move.l  _AbsExecBase,a6             ; A6 = SysBase
  182.  
  183.             ; get misc.resource pointer
  184.         lea     MiscName,a1                 ; open misc.resource
  185.         JSRLIB  OpenResource
  186.         move.l  d0,MiscBase
  187.         beq     init_ret
  188.  
  189.             ; calculate SerPer
  190.         cmp.b   #50,VBlankFrequency(a6)     ; is PAL?
  191.         beq     init_pal
  192.         SetSerPer SerFreq_NTSC              ; set our local SerPer variable (not custom.serper)
  193.         bra     init_serperdone
  194. init_pal
  195.         SetSerPer SerFreq_PAL               ; set out local SerPer variable
  196. init_serperdone
  197.  
  198.         moveq   #1,d0                       ; return TRUE
  199. init_ret
  200.         movem.l (sp)+,init_reg
  201.         rts
  202.  
  203.  
  204. ****************************************************************
  205. *
  206. *   Expunge
  207. *
  208. *   FUNCTION
  209. *       Gets called by CAMD immediately before being
  210. *       UnLoadSeg'ed.
  211. *
  212. *   INPUTS
  213. *       None
  214. *
  215. *   RESULTS
  216. *       None
  217. *
  218. ****************************************************************
  219.  
  220. Expunge
  221.         rts
  222.  
  223.  
  224. ****************************************************************
  225. *
  226. *   OpenPort
  227. *
  228. *   FUNCTION
  229. *       Open a MIDI port.
  230. *
  231. *   INPUTS
  232. *       D0.b - Port number (should always be 0 for this driver)
  233. *       A0 - Xmit function
  234. *       A1 - Recv function
  235. *       A2 - Data
  236. *
  237. *   RESULT
  238. *       D0 - pointer to MidiPortData structure.
  239. *
  240. ****************************************************************
  241.  
  242. op_reg  reg a6
  243.  
  244. OpenPort
  245.         movem.l op_reg,-(sp)
  246.  
  247.         move.l  _AbsExecBase,a6             ; A6 = SysBase
  248.  
  249.         movem.l a0/a1,-(sp)                 ; save a0/a1
  250.         bsr     AllocSerial
  251.         movem.l (sp)+,a0/a1
  252.         ext.l   d0
  253.         beq     op_ret
  254.  
  255.                     ; set SerXmitInt
  256.         move.l  a0,SerXmitInt+si_Code
  257.         move.l  a2,SerXmitInt+si_Data
  258.  
  259.                     ; set SerRecvInt
  260.         move.l  a1,SerRecvInt+si_Code
  261.         move.l  a2,SerRecvInt+si_Data
  262.  
  263.         lea     _custom,a0                  ; A0 = custom
  264.         move.w  #INTF_TBE!INTF_RBF,d1       ; D1 = RBF | TBE mask and int disable
  265.  
  266.                     ; save original TBE and RBF intena settings
  267.         move.w  intenar(a0),d0
  268.         and.w   d1,d0                       ; mask with RBF|TBE mask
  269.         move.w  d0,OldIntEna
  270.  
  271.         move.w  d1,intena(a0)               ; disable TBE and RBF interrupts
  272.         move.w  d1,intreq(a0)               ; clear pending TBE and RBF interrupts
  273.         move.w  SerPer,serper(a0)           ; set serper
  274.  
  275.                     ; set TBE interrupt vector
  276.         moveq   #INTB_TBE,d0
  277.         lea     SerXmitInt,a1
  278.         JSRLIB  SetIntVector
  279.         move.l  d0,SerXmitInt+si_OldInt     ; save old vector
  280.  
  281.                     ; set RBF interrupt vector
  282.         moveq   #INTB_RBF,d0
  283.         lea     SerRecvInt,a1
  284.         JSRLIB  SetIntVector
  285.         move.l  d0,SerRecvInt+si_OldInt     ; save old vector
  286.  
  287.         move.w  #INTF_SET!INTF_RBF,_custom+intena   ; enable RBF
  288.         move.w  #INTF_SET!INTF_TBE,_custom+intreq   ; set a pending TBE
  289.         bclr.b  #CIAB_COMDTR,_ciab+ciapra   ; turn on DTR bit (active low)
  290.  
  291.         lea     MPD0,a0
  292.         move.l  a0,d0                       ; return pointer to MidiPortData
  293.  
  294. op_ret
  295.         movem.l (sp)+,op_reg
  296.         rts
  297.  
  298.  
  299.  
  300. ****************************************************************
  301. *
  302. *   ClosePort
  303. *
  304. *   FUNCTION
  305. *       Close a MIDI port.
  306. *
  307. *   INPUTS
  308. *       D0.b - Port number (always 0 for this driver).
  309. *
  310. *   RESULT
  311. *       None
  312. *
  313. ****************************************************************
  314.  
  315. cp_reg  reg a6
  316.  
  317. ClosePort
  318.         movem.l cp_reg,-(sp)
  319.  
  320.         move.l  _AbsExecBase,a6             ; A6 = SysBase
  321.  
  322.         bsr     WaitSerial
  323.  
  324.         bset.b  #CIAB_COMDTR,_ciab+ciapra           ; turn off DTR bit (active low)
  325.         move.w  #INTF_CLR!INTF_TBE!INTF_RBF,_custom+intena  ; disable RBF & TBE
  326.         move.w  #INTF_CLR!INTF_TBE!INTF_RBF,_custom+intreq  ; clear pending RBF & TBE requests
  327.  
  328.                     ; restore original TBE interrupt vector
  329.         moveq   #INTB_TBE,d0
  330.         move.l  SerXmitInt+si_OldInt,a1
  331.         JSRLIB  SetIntVector
  332.  
  333.                     ; restore original RBF interrupt vector
  334.         moveq   #INTB_RBF,d0
  335.         move.l  SerRecvInt+si_OldInt,a1
  336.         JSRLIB  SetIntVector
  337.  
  338.         move.w  OldIntEna,d0
  339.         beq     cp_nointena
  340.         or.w    #INTF_SET,d0
  341.         move.w  d0,_custom+intena
  342. cp_nointena
  343.  
  344.         bsr     FreeSerial
  345.  
  346.         movem.l (sp)+,cp_reg
  347.         rts
  348.  
  349.  
  350. ****************************************************************
  351. *
  352. *   ActivateXmit
  353. *
  354. *   FUNCTION
  355. *       Activate the transmit interrupt.  There is normally
  356. *       one of these functions for every port in order to
  357. *       reduce table lookup time.
  358. *
  359. *   INPUTS
  360. *       A2 - Data passed to OpenPort() (not used here)
  361. *
  362. *   RESULT
  363. *       None
  364. *
  365. ****************************************************************
  366.  
  367. ActivateXmit
  368.         move.w  #INTF_SET!INTF_TBE,_custom+intena   ; enable TBE interrupt, but leave request pending
  369.         rts
  370.  
  371.  
  372. ****************************************************************
  373. *
  374. *   WaitSerial
  375. *
  376. *   FUNCTION
  377. *       Wait until Amiga serial port TSRE bit is set.  This
  378. *       indicates that the serial shift register is empty.
  379. *
  380. *   INPUTS
  381. *       None
  382. *
  383. *   RESULTS
  384. *       None
  385. *
  386. *   NOTE
  387. *       This function busy waits!!!  It should only be called
  388. *       once the transmit queue has emptied (i.e. TBE has
  389. *       already been set) such that no more than 320us is
  390. *       wasted here.
  391. *
  392. ****************************************************************
  393.  
  394. ws_reg reg
  395.  
  396. WaitSerial
  397.         movem.l ws_reg,-(sp)
  398.  
  399. ws_loop
  400.         move.w  _custom+serdatr,d0
  401.         btst.l  #SERDATB_TSRE,d0
  402.         beq     ws_loop
  403.  
  404.         movem.l (sp)+,ws_reg
  405.         rts
  406.  
  407.  
  408.  
  409. ****************************************************************
  410. *
  411. *   Serial Interrupt Handlers
  412. *
  413. ****************************************************************
  414.  
  415.  
  416. ****************************************************************
  417. *
  418. *   XmitHandler
  419. *
  420. *   FUNCTION
  421. *       Amiga serial port transmit interrupt handler.  Calls
  422. *       the general transmit handler and expects a byte in
  423. *       D0 and a last byte flag in D1.
  424. *
  425. *       When the last byte is detected, the TBE interrupt
  426. *       is disabled, thus deferring calling XmitHandler
  427. *       again until there are some bytes ready to send.
  428. *       CAMD calls ActivateXmit when there are more bytes
  429. *       to send.
  430. *
  431. *   INPUTS
  432. *       A0 - custom
  433. *       A1 - Data
  434. *       A6 - SysBase
  435. *
  436. *   RESULTS
  437. *       None
  438. *
  439. *   NOTE
  440. *       A5 is scratch.
  441. *
  442. ****************************************************************
  443.  
  444. sxh_reg reg a2
  445.  
  446. XmitHandler
  447.         movem.l sxh_reg,-(sp)
  448.  
  449.         movem.l (a1),a2/a5                  ; A2 = Data, A5 = XmitHandler
  450.  
  451. sxh_loop
  452.         move.w  #INTF_CLR!INTF_TBE,_custom+intreq   ; clear TBE interrupt request
  453.  
  454.         jsr     (a5)                        ; returns byte in D0, last byte flag in D1
  455.  
  456.         or.w    #$100,d0                    ; add stop bit
  457.         move.w  d0,_custom+serdat           ; send byte
  458.  
  459.         tst.b   d1                          ; is last byte?
  460.         beq     sxh_notlast
  461.                                             ; xmit queue is empty
  462.         move.w  #INTF_CLR!INTF_TBE,_custom+intena   ; disable TBE interrupt.
  463.         bra     sxh_done                    ; next request remains pending until there are more bytes to send
  464.  
  465. sxh_notlast                                 ; test for another TBE
  466.         btst.b  #INTB_TBE&7,_custom+intreqr+(15-INTB_TBE)/8
  467.         bne     sxh_loop
  468.  
  469. sxh_done
  470.         movem.l (sp)+,sxh_reg
  471.         rts
  472.  
  473.  
  474.  
  475.     if 0
  476.  
  477. ****************************************************************
  478. *
  479. *   XmitHandler
  480. *
  481. *   FUNCTION
  482. *       Amiga serial port transmit interrupt handler.  Called
  483. *       by TBE interrupt vector.  Calls the CAMD transmit
  484. *       handler and expects one of the following return values
  485. *       in d0.w:
  486. *
  487. *           $00mm - a MIDI byte in the lower byte to transmit.
  488. *           $ffff - if no byte to send (queue was empty).
  489. *
  490. *   INPUTS
  491. *       A0 - custom
  492. *       A1 - pointer to SerInt.Data
  493. *       A6 - SysBase
  494. *
  495. *   RESULTS
  496. *       None
  497. *
  498. *   NOTE
  499. *       A5 is scratch.
  500. *
  501. ****************************************************************
  502.  
  503. sxh_reg reg a2
  504.  
  505. XmitHandler
  506.         movem.l sxh_reg,-(sp)
  507.  
  508.         movem.l (a1),a2/a5
  509.  
  510. sxh_loop
  511.         move.w  #INTF_TBE,intreq(a0)    ; clear the interrupt request
  512.  
  513.         jsr     (a5)
  514.  
  515.         or.w    #$100,d0                ; add stop bit
  516.         bmi     sxh_skip                ; if negative, there's no byte to send
  517.  
  518.         lea     _custom,a0              ; see if TBE is still set
  519.         move.w  d0,serdat(a0)           ; send byte
  520.         move.w  intreqr(a0),d0          ; (don't know if btst.b is safe on custom chips)
  521.         and.w   #INTF_TBE,d0                    ;       ^^^ JOE: It's not!!
  522.         bne     sxh_loop
  523.  
  524. sxh_skip
  525.         movem.l (sp)+,sxh_reg
  526.         rts
  527.  
  528.     endc
  529.  
  530.  
  531. ****************************************************************
  532. *
  533. *   RecvHandler
  534. *
  535. *   FUNCTION
  536. *       Amiga serial port receive interrupt handler.  Called
  537. *       by RBF interrupt vector.  Calls the CAMD receive
  538. *       handler with received data until there are no more bytes
  539. *       pending in the serial receive hardware.
  540. *
  541. *   INPUTS
  542. *       A0 - custom
  543. *       A1 - pointer to SerInt.Data
  544. *       A6 - SysBase
  545. *
  546. *   RESULTS
  547. *       None
  548. *
  549. *   NOTE
  550. *       A5 is scratch.
  551. *
  552. ****************************************************************
  553.  
  554. srh_reg reg a2
  555.  
  556. RecvHandler
  557.         movem.l srh_reg,-(sp)
  558.  
  559.         movem.l (a1),a2/a5
  560.         move.w  serdatr(a0),d0
  561.  
  562. srh_loop
  563.         move.w  #INTF_CLR!INTF_RBF,intreq(a0)   ; clear the interrupt request
  564.  
  565.         jsr     (a5)
  566.  
  567.         lea     _custom,a0              ; see if RBF is still set
  568.         move.w  serdatr(a0),d0
  569.         btst.l  #SERDATB_RBF,d0
  570.         bne     srh_loop
  571.  
  572.         movem.l (sp)+,srh_reg
  573.         rts
  574.  
  575.  
  576.  
  577. ****************************************************************
  578. *
  579. *   misc.resource serial stuff
  580. *
  581. ****************************************************************
  582.  
  583. ****************************************************************
  584. *
  585. *   AllocSerial
  586. *
  587. *   FUNCTION
  588. *       Allocate misc.resource channels for the serial port.
  589. *       Call FlushDevice("serial.device") on failure and try
  590. *       again.
  591. *
  592. *   INPUTS
  593. *       A6 - SysBase
  594. *
  595. *   RESULT
  596. *       D0.w - TRUE on success.
  597. *
  598. ****************************************************************
  599.  
  600. as_reg  reg
  601.  
  602. AllocSerial
  603.         movem.l as_reg,-(sp)
  604.  
  605.         JSRLIB  Forbid                      ; remain atomic
  606.  
  607.         bsr     AttemptSerMisc              ; attempt to get serial misc.resource channels
  608.         tst.w   d0
  609.         bne     as_done                     ; if OK, return
  610.  
  611.         lea     SerialName,a1               ; otherwise, FlushDevice("serial.device")
  612.         bsr     FlushDevice
  613.         bsr     AttemptSerMisc              ; and try the serial misc.resource stuff again
  614.  
  615. as_done
  616.         move.w  d0,-(sp)
  617.         JSRLIB  Permit
  618.         move.w  (sp)+,d0
  619.  
  620.         movem.l (sp)+,as_reg
  621.         rts
  622.  
  623.  
  624. ****************************************************************
  625. *
  626. *   AttemptSerMisc
  627. *
  628. *   FUNCTION
  629. *       Attempt to allocate misc.resource channels for the
  630. *       serial port.
  631. *
  632. *   INPUTS
  633. *       None
  634. *
  635. *   RESULT
  636. *       D0.w - TRUE on success.
  637. *
  638. ****************************************************************
  639.  
  640. asm_reg reg a6
  641.  
  642. AttemptSerMisc
  643.         movem.l asm_reg,-(sp)
  644.  
  645.         move.l  MiscBase,a6                 ; A6 = MiscBase
  646.  
  647.         moveq   #MR_SERIALBITS,d0           ; alloc SERIALBITS
  648.         lea     Name,a1
  649.         JSRLIB  AllocMiscResource
  650.         tst.l   d0                          ; if return is non-zero, it's in use
  651.         bne     asm_fail
  652.  
  653.         moveq   #MR_SERIALPORT,d0           ; alloc SERIALPORT
  654.         lea     Name,a1
  655.         JSRLIB  AllocMiscResource
  656.         tst.l   d0                          ; if return is zero, we got it
  657.         beq     asm_ok
  658.  
  659.         moveq   #MR_SERIALBITS,d0           ; free SERIALBITS on SERIALPORT failure
  660.         JSRLIB  FreeMiscResource
  661.  
  662. asm_fail
  663.         moveq   #0,d0
  664.         bra     asm_ret
  665.  
  666. asm_ok
  667.         moveq   #1,d0
  668.  
  669. asm_ret
  670.         movem.l (sp)+,asm_reg
  671.         rts
  672.  
  673.  
  674.  
  675. ****************************************************************
  676. *
  677. *   FreeSerial
  678. *
  679. *   FUNCTION
  680. *       Free misc.resource channels for the serial port.
  681. *
  682. *   INPUTS
  683. *       None
  684. *
  685. *   RESULT
  686. *       None
  687. *
  688. ****************************************************************
  689.  
  690. fs_reg  reg a6
  691.  
  692. FreeSerial
  693.         movem.l fs_reg,-(sp)
  694.  
  695.         move.l  MiscBase,a6                 ; A6 = MiscBase
  696.  
  697.         moveq   #MR_SERIALBITS,d0           ; free SERIALBITS
  698.         JSRLIB  FreeMiscResource
  699.  
  700.         moveq   #MR_SERIALPORT,d0           ; free SERIALPORT
  701.         JSRLIB  FreeMiscResource
  702.  
  703.         movem.l (sp)+,fs_reg
  704.         rts
  705.  
  706.  
  707.  
  708. ****************************************************************
  709. *
  710. *   FlushDevice
  711. *
  712. *   FUNCTION
  713. *       Force expunge of a Device.
  714. *
  715. *   INPUTS
  716. *       A1 - Name of device.
  717. *       A6 - SysBase
  718. *
  719. *   RESULT
  720. *       None
  721. *
  722. *   NOTE
  723. *       Assumes caller has surrounded this call with
  724. *       Forbid/Permit
  725. *
  726. ****************************************************************
  727.  
  728. fd_reg  reg
  729.  
  730. FlushDevice
  731.         movem.l fd_reg,-(sp)
  732.  
  733.         lea     DeviceList(a6),a0
  734.         JSRLIB  FindName
  735.         tst.l   d0                          ; if not in the device list, skip
  736.         beq     fd_ret
  737.  
  738.         move.l  d0,a1                       ; otherwise force expunge
  739.         JSRLIB  RemDevice
  740.  
  741. fd_ret
  742.         movem.l (sp)+,fd_reg
  743.         rts
  744.  
  745.  
  746. MiscName MISCNAME
  747. SerialName dc.b 'serial.device',0
  748.  
  749.         end
  750.